#include <string.h>
#include "sipsiparser.h"
#include "builderplugin.h"
#include "plugindvbfun.h"
#include "pluginnit.h"

#define MANUAL_SCAN_RECV_NIT_MAX	20

int PluginNitStartFilter(builder_nit_control_t* pstNitRecvCntrl)
{
	int s32Ret = -1;
	unsigned char au8Data[16];
	unsigned char au8Mask[16];

	PluginDvbLogcat("PluginNitStartFilter() - entry\r\n");
	memset(au8Data, 0, sizeof(au8Data));
	memset(au8Mask, 0, sizeof(au8Mask));
	au8Data[0] = SIPSI_TID_NIT_ACTUAL;
	au8Mask[0] = 0xFF;
	s32Ret = PluginDvbSetFilter(&pstNitRecvCntrl->m_u32FilterID, SIPSI_PID_NIT, au8Data, au8Mask, 1);
	if(s32Ret == 0)
	{
		PluginDvbLogcat("PluginNitStartFilter() - set filter OK\r\n");
	}
	else
	{
		PluginDvbLogcat("PluginNitStartFilter() - set filter error\r\n");
	}

	PluginDvbLogcat("PluginNitStartFilter() - return, s32Ret = %d\r\n", s32Ret);
	return s32Ret;
}


int PluginNitStart(builder_nit_control_t* pstNitRecvCntrl)
{
	int s32Ret = -1;

	if(pstNitRecvCntrl)
	{
		s32Ret = PluginNitStartFilter(pstNitRecvCntrl);
		pstNitRecvCntrl->m_u32TimeOut = 10;
		pstNitRecvCntrl->m_u32SectionRecvCnt = 0;
		memset(pstNitRecvCntrl->m_au8SecRecvBitmap, 0, sizeof(pstNitRecvCntrl->m_au8SecRecvBitmap));
	}

	return s32Ret;
}

int PluginNitTick(builder_nit_control_t* pstNitRecvCntrl)
{
	int s32Ret = -1;

	if(pstNitRecvCntrl)
	{
		s32Ret = 0;
		pstNitRecvCntrl->m_u32TimeOut--;
		if(pstNitRecvCntrl->m_u32TimeOut == 0)
		{
			if(pstNitRecvCntrl->m_u32FilterID != BUILDER_INVALID_FILTER)
			{
				PluginDvbReleaseFilter(pstNitRecvCntrl->m_u32FilterID);
				pstNitRecvCntrl->m_u32FilterID = BUILDER_INVALID_FILTER;
			}
			pstNitRecvCntrl->m_u32Process = 100;
			if(pstNitRecvCntrl->m_pstNitSection)
			{
				PluginFreeTable(pstNitRecvCntrl->m_pstNitSection);
				pstNitRecvCntrl->m_pstNitSection = NULL;
			}
			s32Ret = -1;
		}
	}
	return s32Ret;
}

int PluginNitRecv(builder_nit_control_t* pstNitRecvCntrl, unsigned int hFilter, unsigned char* pu8Section)
{
	int s32Ret = -1;
	unsigned char u8SectionNum;
	unsigned char u8LastSectionNum;
	builder_section_t* pstSection;
	builder_section_t* pstTmpPrevSection;
	builder_section_t* pstTmpSection;
	unsigned int u32Len;
	unsigned int i;
	unsigned int u32SectionRecvCnt = 0;

	if(pstNitRecvCntrl && hFilter==pstNitRecvCntrl->m_u32FilterID)
	{
		s32Ret = 0;
		pstNitRecvCntrl->m_u32TimeOut = 10;
		pstNitRecvCntrl->m_u32SectionRecvCnt++;
		u8SectionNum = SiPsiGetSectionNo(pu8Section);
		u8LastSectionNum = SiPsiGetLastSectionNo(pu8Section);
		if(pstNitRecvCntrl->m_au8SecRecvBitmap[u8SectionNum] == 0)
		{
			u32Len = SiPsiGetSectionLength(pu8Section) + 3;
			pstSection = PluginDvbMemAlloc(sizeof(builder_section_t) + u32Len);
			if(pstSection)
			{
				memcpy(pstSection->m_au8Section, pu8Section, u32Len);
				pstTmpPrevSection = pstNitRecvCntrl->m_pstNitSection;
				if(pstTmpPrevSection && SiPsiGetSectionNo(pstTmpPrevSection->m_au8Section)<u8SectionNum)
				{
					pstTmpSection = pstTmpPrevSection->m_pstNext;
					while(pstTmpSection)
					{
						if(SiPsiGetSectionNo(pstTmpSection->m_au8Section)>u8SectionNum)
							break;
						pstTmpPrevSection = pstTmpSection;
						pstTmpSection = pstTmpPrevSection->m_pstNext;
					}
					pstSection->m_pstNext = pstTmpSection;
					pstTmpPrevSection->m_pstNext = pstSection;
				}
				else
				{
					pstSection->m_pstNext = pstNitRecvCntrl->m_pstNitSection;
					pstNitRecvCntrl->m_pstNitSection = pstSection;
				}
			}
			else
			{	
				PluginDvbLogcat("PluginNitRecv() -malloc section failed\r\n");
			}
			pstNitRecvCntrl->m_au8SecRecvBitmap[u8SectionNum] = 1;
		}

		for(i=0; i<=u8LastSectionNum; i++)
		{
			if(pstNitRecvCntrl->m_au8SecRecvBitmap[i] == 1)
			{
				u32SectionRecvCnt++;
			}
		}

		if(u32SectionRecvCnt > u8LastSectionNum)
		{
			PluginDvbReleaseFilter(pstNitRecvCntrl->m_u32FilterID);
			pstNitRecvCntrl->m_u32FilterID = BUILDER_INVALID_FILTER;
			pstNitRecvCntrl->m_u32Process = 100;
		}
		else if(pstNitRecvCntrl->m_u32SectionRecvCnt > MANUAL_SCAN_RECV_NIT_MAX)
		{
			PluginDvbLogcat("PluginNitRecv() -recv section time out\r\n");
			PluginDvbReleaseFilter(pstNitRecvCntrl->m_u32FilterID);
			pstNitRecvCntrl->m_u32FilterID = BUILDER_INVALID_FILTER;
			pstTmpSection = pstNitRecvCntrl->m_pstNitSection;
			do
			{
				pstSection = pstTmpSection;
				pstTmpSection = pstSection->m_pstNext;
				PluginDvbMemFree(pstSection);
			}while(pstTmpSection);
			pstNitRecvCntrl->m_pstNitSection = NULL;
			pstNitRecvCntrl->m_u32Process = 100;
			s32Ret = -1;		
		}
		else
		{
			pstNitRecvCntrl->m_u32Process = u32SectionRecvCnt*100/(u8LastSectionNum+1);
		}
	}

	return s32Ret;
}

int PluginNitGetProcess(builder_nit_control_t* pstNitRecvCntrl, unsigned int* pu32Process)
{
	int s32Ret = -1; 

	if(pstNitRecvCntrl)
	{
		*pu32Process = pstNitRecvCntrl->m_u32Process;
		s32Ret = 0;
	}

	return s32Ret;
}

int PluginNitStop(builder_nit_control_t* pstNitRecvCntrl)
{
	int s32Ret;
	
	s32Ret = PluginNitReset(pstNitRecvCntrl);

	return s32Ret;
}

int PluginNitReset(builder_nit_control_t* pstNitRecvCntrl)
{
	int s32Ret = -1;

	if(pstNitRecvCntrl)
	{
		s32Ret = -1;
		pstNitRecvCntrl->m_u32TimeOut = 0;
		if(pstNitRecvCntrl->m_u32FilterID != BUILDER_INVALID_FILTER)
		{
			PluginDvbReleaseFilter(pstNitRecvCntrl->m_u32FilterID);
			pstNitRecvCntrl->m_u32FilterID = BUILDER_INVALID_FILTER;
		}

		if(pstNitRecvCntrl->m_pstNitSection)
		{
			PluginFreeTable(pstNitRecvCntrl->m_pstNitSection);
			pstNitRecvCntrl->m_pstNitSection = NULL;
		}

		memset(pstNitRecvCntrl->m_au8SecRecvBitmap, 0, sizeof(pstNitRecvCntrl->m_au8SecRecvBitmap));
		pstNitRecvCntrl->m_u32SectionRecvCnt = 0;

		pstNitRecvCntrl->m_u32Process = 0;
	}

	return s32Ret;
}

int PluginNitGetSections(builder_nit_control_t* pstNitRecvCntrl, builder_section_t** ppstBat)
{
	int s32Ret = -1;
	
	if(pstNitRecvCntrl)
	{
		*ppstBat = pstNitRecvCntrl->m_pstNitSection;
		pstNitRecvCntrl->m_pstNitSection = NULL;
	}

	return s32Ret;
}

static int PluginNitCheckTunerList(builder_tuner_t* pstFreqList, unsigned int* pu32Cnt)
{
	unsigned int u32Jump;
	unsigned int i;
	int s32Ret = -1;

	PluginDvbLogcat("PluginNitCheckTunerList() - entry, pstFreqList = %p, pu32Cnt = %p\r\n", pstFreqList, pu32Cnt);	
	if(pstFreqList && pu32Cnt)
	{
		s32Ret = 0;
		u32Jump = 0;
		for(i=0; i<*pu32Cnt; i++)
		{
			s32Ret = PluginCheckTunerInfo(&pstFreqList[i]);
			if(s32Ret == 0)
			{
				if(u32Jump > 0)
					memcpy(&pstFreqList[i-u32Jump], &pstFreqList[i], sizeof(builder_tuner_t));
			}
			else
			{
				u32Jump++;
			}
		}
		*pu32Cnt = *pu32Cnt - u32Jump;
	}
	PluginDvbLogcat("PluginNitCheckTunerList() - return, s32Ret = %d\r\n", s32Ret);
	return s32Ret;
}

int PluginNitGetStreamParam(builder_section_t* pstSection, unsigned int u32Index, builder_tuner_t* pstTunerInfo)
{
	int s32Ret = -1;
	unsigned int u32Cnt = 0;
	unsigned int u32CurSectionTsCnt;
	sipsi_dvb_stream_t stStream;
	sipsi_cable_tunerinfo_t stCableTunerInfo;

	PluginDvbLogcat("PluginNitGetStreamParam() - entry, u32Index = %d, pstTunerInfo = %p\r\n", u32Index, pstTunerInfo);
	if(pstTunerInfo)
	{
		while(pstSection)
		{
			u32CurSectionTsCnt = SiPsiNITGetTSCount(pstSection->m_au8Section);
			if((u32Cnt+u32CurSectionTsCnt) <= u32Index)	////turn to next section
			{
				pstSection = pstSection->m_pstNext;
				u32Cnt += u32CurSectionTsCnt;
			}
			else
			{
				break;
			}
		}
		if(pstSection && u32Index >= u32Cnt)
		{
			u32Index -= u32Cnt;
			SiPsiNITGetTsStream(pstSection->m_au8Section, &stStream, u32Index);
			s32Ret = SiPsiNITGetDeliveryTuneInfo(&stStream, &stCableTunerInfo);	////one ts information
			PluginDvbLogcat("PluginNitGetStreamParam() - SiPsiNITGetDeliveryTuneInfo return, s32Ret = %d\r\n", s32Ret);
			if(s32Ret == 0)
			{
				pstTunerInfo->m_u32Freq = stCableTunerInfo.m_u32Frequency;
				pstTunerInfo->m_u32Mod = stCableTunerInfo.m_u32Modulation;
				pstTunerInfo->m_u32Sym = stCableTunerInfo.m_u32SymbolRate;
				pstTunerInfo->m_u32Bandwidth = 8;
				pstTunerInfo->m_u32Tunertype = BUILDER_TUNER_DVBT;
				PluginDvbLogcat("PluginNitGetStreamParam() - return, pstTunerInfo->m_u32Freq = %d, pstTunerInfo->m_u32Mod = %d, pstTunerInfo->m_u32Sym = %d\r\n", 
					pstTunerInfo->m_u32Freq, pstTunerInfo->m_u32Mod, pstTunerInfo->m_u32Sym);
			}
			else
			{
				memset(pstTunerInfo, 0, sizeof(builder_tuner_t));
			}
		}
	}
	PluginDvbLogcat("PluginNitGetStreamParam() - return, s32Ret = %d\r\n", s32Ret);
	return s32Ret;
}

int PluginNitGetStreamCount(builder_section_t* m_pstSections, unsigned int* pu32Cnt)
{
	int s32Ret = -1;
	builder_section_t* pstSection;

	PluginDvbLogcat("PluginNitGetStreamCount() - entry, pu32Cnt = %p\r\n", pu32Cnt);
	if(pu32Cnt)
	{
		*pu32Cnt = 0;
		pstSection = m_pstSections;
		while(pstSection)
		{
			*pu32Cnt += SiPsiNITGetTSCount(pstSection->m_au8Section);
			PluginDvbLogcat("PluginNitGetStreamCount() - SiPsiNITGetTSCount, *pu32Cnt = %d\r\n", *pu32Cnt);
			pstSection = pstSection->m_pstNext;
			PluginDvbLogcat("PluginNitGetStreamCount()	pstSection = %p\r\n", pstSection);
		}
		s32Ret = 0;
	}
	PluginDvbLogcat("PluginNitGetStreamCount() - return, pu32Cnt = %d\r\n", *pu32Cnt);
	PluginDvbLogcat("PluginNitGetStreamCount() - return, s32Ret = %d\r\n", s32Ret);
	return s32Ret;
}

int PluginNitGetTunerList(builder_nit_control_t* pstNitRecvCntrl, builder_tuner_t** ppstTunerList, unsigned int* pu32Cnt)
{
	int s32Ret = -1;
	unsigned int u32TsCnt;
	unsigned int i;
	
	PluginDvbLogcat("PluginNitGetTunerList() - entry\r\n");
	s32Ret = PluginNitGetStreamCount(pstNitRecvCntrl->m_pstNitSection, &u32TsCnt);
	if(s32Ret == 0 && u32TsCnt>0)
	{
		*ppstTunerList = PluginDvbMemAlloc(u32TsCnt*sizeof(builder_tuner_t));
		if(*ppstTunerList)
		{
			for(i=0; i<u32TsCnt; i++)
				PluginNitGetStreamParam( pstNitRecvCntrl->m_pstNitSection, i, (*ppstTunerList)+i);
			PluginNitCheckTunerList(*ppstTunerList, &u32TsCnt);
			*pu32Cnt = u32TsCnt;
		}
		else
		{
			PluginDvbLogcat("PluginNitGetTunerList() - malloc error\r\n");
		}
	}
	else
	{
		PluginDvbLogcat("PluginNitGetTunerList() - get Nit stream count error\r\n");
	}
	PluginDvbLogcat("PluginNitGetTunerList() - return, s32Ret = %d\r\n", s32Ret);
	return s32Ret;
}

